// 基础配置
import { BASE_URL } from '@/utils/config.js'

// 请求拦截器ID
let requestInterceptorId = null
let responseInterceptorId = null

// ====== 认证与刷新工具 ======
// 解析 JWT 载荷
function parseJwtPayload(token) {
  try {
    const payloadBase64 = token.split('.')[1]
    const json = decodeURIComponent(
      atob(payloadBase64)
        .split('')
        .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
        .join('')
    )
    return JSON.parse(json)
  } catch (e) {
    return null
  }
}

// 判断 token 是否过期（预留60秒缓冲）
function isTokenExpired(token) {
  if (!token) return true
  const payload = parseJwtPayload(token)
  if (!payload || !payload.exp) return true
  const now = Math.floor(Date.now() / 1000)
  return payload.exp - now <= 60
}

// 刷新并保存 token（直接调用刷新接口，避免循环依赖）
async function refreshAccessToken() {
  return new Promise((resolve, reject) => {
    const storedRefreshToken = uni.getStorageSync('refreshToken')
    if (!storedRefreshToken) {
      return reject(new Error('No refresh token'))
    }
    uni.request({
      url: BASE_URL + '/auth/refresh-token',
      method: 'POST',
      header: { 'Content-Type': 'application/json' },
      data: { refreshToken: storedRefreshToken, forceRefresh: false },
      timeout: 30000,
      success: (res) => {
        // 兼容两种返回结构：{accessToken,...} 或 {data:{accessToken,...}}
        const payload = res?.data?.data || res?.data || {}
        const accessToken = payload.accessToken
        const newRefreshToken = payload.refreshToken || storedRefreshToken
        const user = payload.user
        if (accessToken) {
          uni.setStorageSync('token', accessToken)
          if (newRefreshToken) uni.setStorageSync('refreshToken', newRefreshToken)
          if (user) uni.setStorageSync('userInfo', user)
          resolve(accessToken)
        } else {
          reject(new Error('Refresh token response invalid'))
        }
      },
      fail: (err) => reject(err)
    })
  })
}

// 发送前确保本地 token 可用
async function ensureValidToken() {
  const token = uni.getStorageSync('token')
  if (!token || isTokenExpired(token)) {
    try {
      await refreshAccessToken()
    } catch (e) {
      // 刷新失败则清空本地认证，交由后续请求失败处理
      uni.removeStorageSync('token')
    }
  }
}

// 清理ASCII字符串函数
function cleanAsciiString(str) {
  if (typeof str !== 'string') return str
  return str.replace(/[\x00-\x1F\x7F]/g, '') // 只清理控制字符
}

// 清理对象函数
function cleanObject(obj) {
  if (typeof obj !== 'object' || obj === null) return obj
  const cleaned = {}
  Object.keys(obj).forEach(key => {
    const value = obj[key]
    if (typeof value === 'string') {
      cleaned[key] = cleanAsciiString(value)
    } else if (typeof value === 'object' && value !== null) {
      cleaned[key] = cleanObject(value)
    } else {
      cleaned[key] = value
    }
  })
  return cleaned
}

// 获取平台信息
const getPlatform = () => {
  // #ifdef MP-WEIXIN
  return 'mp-weixin'
}

// 检查网络状态
const checkNetworkStatus = () => {
  return new Promise((resolve) => {
    uni.getNetworkType({
      success: (res) => {
        console.log('网络类型:', res.networkType)
        if (res.networkType === 'none') {
          resolve(false)
        } else {
          resolve(true)
        }
      },
      fail: () => {
        resolve(false)
      }
    })
  })
}

// 移除已存在的拦截器
if (requestInterceptorId) {
  uni.removeInterceptor('request', requestInterceptorId)
}
if (responseInterceptorId) {
  uni.removeInterceptor('request', responseInterceptorId)
}

// 请求拦截器
requestInterceptorId = uni.addInterceptor('request', {
  invoke(args) {
    console.log('=== 请求拦截器开始 ===')
    console.log('原始URL:', args.url)
    console.log('当前平台:', getPlatform())
    
    // 添加基础URL
    if (!args.url.startsWith('http')) {
      args.url = BASE_URL + args.url
    }
    
    // 设置超时时间 - 增加延迟容忍度（小程序建议>=60000ms）
    args.timeout = getPlatform() === 'mp-weixin' ? 60000 : 45000
    
    // 设置请求头
    args.header = {
      'Content-Type': 'application/json',
      ...args.header
    }
    
    // 清理请求头
    args.header = cleanObject(args.header)
    
    // 添加token
    const token = uni.getStorageSync('token')
    if (token) {
      const cleanToken = cleanAsciiString(token)
      if (cleanToken) {
        args.header.Authorization = `Bearer ${cleanToken}`
      }
    }
    
    console.log('最终URL:', args.url)
    console.log('请求头:', args.header)
    console.log('请求方法:', args.method || 'GET')
    console.log('超时时间:', args.timeout)
    console.log('=== 请求拦截器结束 ===')
  }
})

// 响应拦截器
responseInterceptorId = uni.addInterceptor('request', {
  success(res) {
    console.log('=== 响应拦截器成功 ===')
    console.log('状态码:', res.statusCode)
    console.log('响应数据:', res.data)
    
    if (res.statusCode === 200) {
      if (res.data && res.data.code === 200) {
        console.log('业务请求成功')
        return res.data
      } else {
        const errorMsg = res.data?.message || res.data?.msg || '请求失败'
        console.error('业务错误:', errorMsg)
        uni.showToast({
          title: errorMsg,
          icon: 'none'
        })
        return Promise.reject(res.data)
      }
    }
    
    console.error('HTTP错误:', res.statusCode)
    
    // 小程序特殊错误处理
    let errorMsg = '网络请求失败'
    if (getPlatform() === 'mp-weixin') {
      if (res.statusCode === 404) {
        errorMsg = '接口不存在'
      } else if (res.statusCode === 500) {
        errorMsg = '服务器内部错误'
      } else if (res.statusCode === 403) {
        errorMsg = '访问被拒绝'
      }
    }
    
    uni.showToast({
      title: errorMsg,
      icon: 'none'
    })
    return Promise.reject(res)
  },
  fail(err) {
    console.error('=== 响应拦截器失败 ===')
    console.error('错误详情:', err)
    
    // 小程序特殊错误处理
    let errorMsg = '网络异常'
    let showDomainTip = false
    
    if (getPlatform() === 'mp-weixin') {
      if (err.errMsg) {
        if (err.errMsg.includes('url not in domain list')) {
          errorMsg = '域名未配置，请检查小程序域名白名单'
          showDomainTip = true
          
          // 开发环境提示
          console.warn('开发环境提示：请在微信开发者工具中勾选"不校验合法域名"')
        } else if (err.errMsg.includes('timeout')) {
          errorMsg = '请求超时'
        } else if (err.errMsg.includes('fail')) {
          errorMsg = '网络连接失败'
        } else if (err.errMsg.includes('ssl')) {
          errorMsg = 'SSL证书错误'
        } else if (err.errMsg.includes('request:fail')) {
          errorMsg = '网络请求失败'
        }
      }
    }
    
    console.error('最终错误信息:', errorMsg)
    
    if (showDomainTip) {
      uni.showModal({
        title: '域名配置问题',
        content: '检测到域名白名单问题，请按以下步骤解决：\n\n1. 在开发者工具中勾选"不校验合法域名"\n2. 或在微信后台配置域名白名单',
        showCancel: false,
        confirmText: '知道了'
      })
    } else {
      uni.showToast({
        title: errorMsg,
        icon: 'none',
        duration: 3000
      })
    }
    
    return Promise.reject(err)
  }
})

// 核心请求函数
function request({ url, method = 'GET', data = {}, header = {} , _retried = false }) {
  return new Promise(async (resolve, reject) => {
    console.log('=== 开始网络请求 ===')
    console.log('请求URL:', url)
    console.log('请求方法:', method)
    console.log('请求数据:', data)
    
    // 发送前确保 token 有效
    try {
      await ensureValidToken()
    } catch (e) {
      console.warn('确保token有效失败（可忽略继续请求）:', e)
    }

    // 检查网络状态
    const hasNetwork = await checkNetworkStatus()
    if (!hasNetwork) {
      console.error('网络连接不可用')
      uni.showToast({
        title: '网络连接不可用',
        icon: 'none'
      })
      reject(new Error('网络连接不可用'))
      return
    }
    
    // 清理请求数据
    const cleanData = cleanObject(data)
    
    // 在底层也设置超时，避免被上层覆盖
    const requestTimeout = getPlatform() === 'mp-weixin' ? 60000 : 45000

    const doRequest = () => uni.request({
      url,
      method,
      data: cleanData,
      header,
      timeout: requestTimeout,
      success: res => {
        console.log('=== 请求成功 ===')
        console.log('响应结果:', res)
        // 401 尝试刷新并重试一次
        if (res && res.statusCode === 401 && !_retried) {
          console.warn('检测到401，尝试刷新token并重试...')
          refreshAccessToken()
            .then(() => {
              // 成功刷新后重试一次
              request({ url, method, data: cleanData, header, _retried: true })
                .then(resolve)
                .catch(reject)
            })
            .catch(err => {
              console.error('刷新token失败:', err)
              reject(res)
            })
          return
        }
        resolve(res.data)
      },
      fail: err => {
        console.error('=== 请求失败 ===')
        console.error('错误详情:', err)
        // 编码错误检查
        if (err.errMsg && err.errMsg.includes('setRequestHeader') && err.errMsg.includes('ISO-8859-1')) {
          console.error('检测到编码错误，尝试清理请求头...')
        }
        reject(err)
      }
    })

    doRequest()
  })
}

// HTTP方法封装
const http = {
  get(url, params = {}) {
    return request({
      url,
      method: 'GET',
      data: params
    })
  },
  
  post(url, data = {}, options = {}) {
    return request({
      url,
      method: 'POST',
      data,
      ...options
    })
  },
  
  put(url, data = {}) {
    return request({
      url,
      method: 'PUT',
      data
    })
  },
  
  delete(url, data = {}) {
    return request({
      url,
      method: 'DELETE',
      data
    })
  },
  
  // 文件上传
  upload(url, filePath, formData = {}) {
    return new Promise(async (resolve, reject) => {
      // 检查网络状态
      const hasNetwork = await checkNetworkStatus()
      if (!hasNetwork) {
        uni.showToast({
          title: '网络连接不可用',
          icon: 'none'
        })
        reject(new Error('网络连接不可用'))
        return
      }
      
      const token = uni.getStorageSync('token')
      const header = {
        'Content-Type': 'multipart/form-data'
      }
      
      if (token) {
        header.Authorization = `Bearer ${cleanAsciiString(token)}`
      }
      
      uni.uploadFile({
        url: url.startsWith('http') ? url : BASE_URL + url,
        filePath,
        name: 'file',
        formData,
        header,
        success: res => {
          console.log('上传成功:', res)
          try {
            const data = JSON.parse(res.data)
            resolve(data)
          } catch (e) {
            resolve(res.data)
          }
        },
        fail: err => {
          console.error('上传失败:', err)
          reject(err)
        }
      })
    })
  },
  
  // 测试网络连接
  testConnection() {
    return new Promise(async (resolve, reject) => {
      try {
        console.log('=== 开始网络连接测试 ===')
        
        const hasNetwork = await checkNetworkStatus()
        if (!hasNetwork) {
          reject(new Error('网络连接不可用'))
          return
        }
        
        console.log('网络状态正常，开始API测试...')
        
        // 测试基础连接
        const testResult = await uni.request({
          url: BASE_URL + '/auth/test',
          method: 'GET',
          timeout: getPlatform() === 'mp-weixin' ? 30000 : 20000
        })
        
        console.log('API测试结果:', testResult)
        
        if (testResult.statusCode === 200) {
          resolve({ success: true, message: '连接正常' })
        } else {
          reject(new Error(`连接异常: ${testResult.statusCode}`))
        }
      } catch (error) {
        console.error('网络连接测试失败:', error)
        reject(error)
      }
    })
  }
}

export { ensureValidToken, refreshAccessToken }
export default http
